package com.education.service.system;

import com.alibaba.fastjson.JSONObject;
import com.education.common.exception.BusinessException;
import com.education.common.model.AdminUserSession;
import com.education.common.model.OnlineUser;
import com.education.common.model.OnlineUserManager;
import com.education.common.utils.*;
import com.education.mapper.system.SystemAdminMapper;
import com.education.service.BaseService;
import com.education.service.websocket.SystemWebSocketHandler;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author 余一
 * @Description
 * @date 2021/7/1 11:40
 */
@Service
public class SystemAdminService extends BaseService<SystemAdminMapper> {
    @Autowired
    private SystemMenuService menuService;
    @Autowired
    private SystemAdminRoleService systemAdminRoleService;
    @Autowired
    private SystemRoleMenuService systemRoleMenuService;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private SystemWebSocketHandler webSocketHandler;
    @Resource
    private OnlineUserManager onlineUserManager;

    public Result login(String userName,String password){
        Result result = new Result();
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
        try {
            subject.login(token);
            result.setCode(ResultCode.SUCCESS);
            result.setMessage("登录成功！");
        }catch (Exception e){
            logger.error("登录失败",e);
            result.setCode(ResultCode.FAIL);
            if (e instanceof UnknownAccountException){
                result.setMessage("用户不存在");
            }else {
                result.setMessage("用户名或密码错误");
            }
            Throwable throwable = e.getCause();
            if (ObjectUtils.isNotEmpty(throwable)) {
                if (throwable instanceof BusinessException) {
                    result.setMessage(throwable.getMessage());
                }
            }
        }
        return result;
    }

    public void loadUserMenuAndPermission(AdminUserSession userSession){
        //菜单列表
        List<Map> menuList = null;
        if (userSession.isSuperAdmin()){
            //如果是超级管理员，加载所有权限
           menuList = menuService.queryList(null);
        }else {
            //根据用户id加载 用户角色
            Integer id = (Integer) userSession.getUserMap().get("id");
            List<Map> roleList = systemAdminRoleService.findRoleListByAdminId(id);
            if (ObjectUtils.isNotEmpty(roleList)){
                HashSet<Integer> roleIds = new HashSet<>();
                roleList.forEach(roleInfo -> {
                    roleIds.add((Integer) roleInfo.get("role_id"));
                });
                userSession.setRoleIds(roleIds);

                HashMap params = new HashMap<>();
                params.put("roleIds",roleIds);
                menuList = systemRoleMenuService.findMenuListByRoleIds(params);
            }

        }

        //遍历菜单获取权限标识
        menuList.forEach(menu -> {
            String permission = (String) menu.get("permission");
            if (ObjectUtils.isNotEmpty(permission)) {
                userSession.addPermission(permission);
            }
        });

        List<Map> treeData = MapTreeUtils.buildTreeData(menuList);
        userSession.setMenuList(treeData);
        this.updateShiroCacheUserInfo(userSession);
    }

    @Override
    @Transactional
    public Result saveOrUpdate(Map dataMap) {
       String message = "";
        try {
            //校验手机号格式
            String mobile = (String) dataMap.get("mobile");
            if (ObjectUtils.isNotEmpty(mobile)) {
                boolean compile = RegexUtils.compile(RegexUtils.MOBILE_REGEX, mobile);
                if(!compile){
                    return Result.fail(ResultCode.FAIL,"非法手机号");
                }
            }

            List<Integer> roleIds = (List<Integer>) dataMap.get("roleIds");
            dataMap.remove("roleIds");

            Integer adminId = null;
            Date now = new Date();
            if (ObjectUtils.isNotEmpty(dataMap.get("id"))){ //修改用户
                dataMap.put("update_date",now);
                adminId = (Integer) dataMap.get("id");
                systemAdminRoleService.deleteByAdminId(adminId);
                this.update(dataMap);
                message = "修改成功";
            }else { //添加用户
                String password = (String) dataMap.get("password");
                if (ObjectUtils.isEmpty(password)) {
                    return Result.fail(ResultCode.FAIL,"请输入密码");
                }
                String confirmPassword = (String) dataMap.get("confirmPassword");
                if (ObjectUtils.isEmpty(confirmPassword)) {
                    return Result.fail(ResultCode.FAIL,"请再次输入密码");
                }
                if(!password.equals(confirmPassword)){
                    return Result.fail(ResultCode.FAIL,"两次输入密码不一致");
                }
                dataMap.remove("confirmPassword");
                //保存管理员信息
                String encrypt = EncryptUtil.encodeSalt(EncryptUtil.generatorKey());//生成密码hash
                password = EncryptUtil.getMd5(password, encrypt);//生成加密后的密码
                dataMap.put("password",password);
                dataMap.put("encrypt",encrypt);
                dataMap.put("create_date",now);
                message = "添加管理员";
                adminId = this.save(dataMap);
            }

            //给用户关联角色
            List<Map> roleList = new ArrayList<>();
            for (Integer roleId : roleIds) {
                Map modelMap = new HashMap();
                modelMap.put("admin_id",adminId);
                modelMap.put("role_id",roleId);
                roleList.add(modelMap);
            }
            Map roleMap = new HashMap();
            roleMap.put("list",roleList);
            systemAdminRoleService.batchSave(roleMap);
            return Result.success(ResultCode.SUCCESS,message + "成功");
        }catch (Exception e){
            logger.error(message + "异常",e);
            throw new BusinessException(new ResultCode(ResultCode.FAIL,message + "异常"));
        }
    }

    public int update(Map params) {
          return mapper.update(params);
    }

    public Result getRoleIdsByAdminId(Integer adminId) {
        List<Map> adminRoles = systemAdminRoleService.getRoleIdsByAdminId(adminId);
        List<Integer> roleIds = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(adminRoles)) {
            roleIds = adminRoles.stream()
                    .map(item -> (Integer)item.get("role_id"))
                    .collect(Collectors.toList());
        }
        return Result.success(roleIds);
    }

    @Override
    @Transactional
    public Result deleteById(Map modelMap) {
        try {
            Boolean super_user = (Integer) modelMap.get("super_flag") == 1 ? true : false;
            if (super_user){
                return Result.fail(ResultCode.FAIL,"不能删除超级管理员");
            }
            systemAdminRoleService.deleteByAdminId((Integer) modelMap.get("id"));
            return super.deleteById(modelMap);
        }catch (Exception e){
            logger.error(e.getMessage());
            return Result.fail(ResultCode.FAIL,"删除失败");
        }

    }

    public Result resettingPassword(Map userInfo) {
        String password = (String) userInfo.get("password");
        String confirmPassword = (String) userInfo.get("confirmPassword");
        if (!password.equals(confirmPassword)) {
            return Result.fail(ResultCode.FAIL,"两次输入密码不一致！");
        }
        String encrypt = (String) userInfo.get("encrypt");
        password = EncryptUtil.getMd5(password,encrypt);
        Integer id = (Integer) userInfo.get("id");
        userInfo.clear();
        userInfo.put("password",password);
        userInfo.put("id",id);
        update(userInfo);
        return Result.success(ResultCode.SUCCESS,"密码重置成功！");
    }

    /**
     * 查看用户容器中是否已存在该用户，存在表示已在其他设备登录
     * 如果存在，使用webSocket异步发送一条消息推送
     * @param userId
     */
    public void checkOnlineUser(Integer userId){
        OnlineUser onlineUser = onlineUserManager.getOnlineUser(userId);
        if (ObjectUtils.isNotEmpty(onlineUser)) {
            //发送一条消息推送
            String sessionId = onlineUser.getSessionId();
            //踢出原来的用户信息
            onlineUserManager.removeOnlineUser(userId);
            String ip = IpUtils.getAddressIp(request);
            taskManager.pushTask(() -> {
                try{
                    Thread.sleep(1000);
                    String address = IpUtils.getAddressByIp(ip);
                    address = address == null ? "在其他设备上" : address;
                    ResultCode resultCode = new ResultCode(ResultCode.SUCCESS, "您的帐号已在" + address + "登录，5秒后将自动下线，如非被人操作，请修改密码");
                    String message = JSONObject.toJSONString(resultCode);
                    webSocketHandler.sendMessage(sessionId,message);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            });

        }

    }

}
